#!/usr/bin/env python
#
# Copyright (c) 2010 Josef Hardi. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# encoding: utf-8

"""
    Robo Issue Miner
    
    This robot crawls the Chromium issue reports and fetches the several
    labels information.
    
    @copyright: 2010 Josef Hardi
    @license: GNU GPL
"""

__author__ = 'Josef Hardi <josef.hardi@gmail.com>'

import os
import sys
from dateutil.parser import parse
from optparse import OptionParser

import csv
import gdata.projecthosting.client

import chromiumhosting.data


ISO8601_FORMAT = '%Y-%m-%dT%H:%M:%S'

USAGE = 'usage: ' + os.path.basename(sys.argv[0]) + ' [options] [args]'
DESCRIPTION = 'Chromium issue tracking parser.'

CSV_HEADER=('id,area,type,mstone,status,owner,'
            'opened,opened_timestamp,'
            'assigned,assigned_timestamp,'
            'started,started_timestamp,'
            'closed,closed_timestamp')


class IssueLabel(object):
  """"""
  _split_char = "-"
  category = {}
  
  def __init__(self, labels):
    """"""
    self.category = {}
    for label in labels:
      try:
        name, value = label.text.split(self._split_char, 1)
        if self.category.get(name, None):
          self.category[name] = "%s, %s" % (self.category[name], value)
        else:
          self.category[name] = value
      except AttributeError:
        pass
      except ValueError:
        pass
  
  def __getattr__(self, name):
    try:
      return self.category[name]
    except KeyError:
      return ""


class CommentStatusUpdateDateTime(object):
  """"""
  category = {}
  
  def __init__(self, comments):
    """"""
    self.category = {}
    for comment in comments:
      try:
        name = comment.updates.status.text
        value = comment.published.text
        if self.category.get(name, None):
          self.category[name] = "%s*" % value   # if found more than once
        else:
          self.category[name] = value
      except AttributeError:
        pass
  
  def __getattr__(self, name):
    try:
      return self.category[name]
    except KeyError:
      return ""


def print_csv(project_name, canned_query=None, issue_id=None, owner=None,
              status=None, max_results=None, include_header=True):
  """"""
  client = gdata.projecthosting.client.ProjectHostingClient()
  query = gdata.projecthosting.client.Query(canned_query=canned_query,
                                            issue_id=issue_id,
                                            owner=owner,
                                            status=status,
                                            max_results=max_results)
  feed = client.get_issues(project_name=project_name,
                           desired_class=chromiumhosting.data.ChromiumIssueFeed,
                           query=query)
  
  if include_header:
    print CSV_HEADER
  
  for issue in feed.entry:
    label = IssueLabel(issue.label)
    comments_feed = client.get_comments(project_name, issue.id.text)
    comment = CommentStatusUpdateDateTime(comments_feed.entry)
    
    owner = getattr(issue, "owner", False)
    username = owner.username.text if owner else ""
    
    closed = getattr(issue, "closedDate", False)
    closedDate = closed.text if closed else ""
    
    try:
      print '%s,"%s","%s","%s","%s","%s","%s",%d,"%s",%d,"%s",%d,"%s",%d' % \
            (issue.id.text, label.Area, label.Type, label.Mstone,
            issue.status.text, username,
            issue.published.text, _unix_timestamp(issue.published.text),
            comment.Assigned, _unix_timestamp(comment.Assigned),
            comment.Started, _unix_timestamp(comment.Started),
            closedDate, _unix_timestamp(closedDate))
    except AttributeError:
      pass


def _unix_timestamp(datestr):
  """Create timestamp from date string"""
  if datestr.strip():
    date, microsecond = datestr.split('.')
    return int(parse(date).strftime('%s'))
  else:
    return 0


def main():
  parser = OptionParser(usage=USAGE)
  parser.description=DESCRIPTION
  parser.add_option("-c", "--canned-query",
                   dest="canned_query",
                   default=None,
                   help="return issues based on a canned query identifier, \
                         e.g., all, open, owned, reported, starred, new, \
                         to-verify.")
  parser.add_option("-i", "--issue",
                   dest="id",
                   default=None,
                   help="the issue to return based on the issue id.")
  parser.add_option("-o", "--owner",
                   dest="owner",
                   default=None,
                   help="return issues based on the owner of the issue. \
                         For Gmail users, this will be the part of the email \
                         preceding the '@' sign.")
  parser.add_option("-s", "--status",
                   dest="status",
                   default=None,
                   help="return issues based on the status of the issue.")
  parser.add_option("-N", "--max-results",
                   dest="max_results",
                   default=None,
                   help="maximum number of results to be retrieved.")
  parser.add_option("--no-header",
                   dest="header",
                   default="store_true",
                   action="store_false",
                   help="print CSV output without the header.")
  
  (options, args) = parser.parse_args()
  
  if len(args) != 1:
    parser.error("incorrect number of arguments")
  
  print_csv(args[0], options.canned_query, options.id, options.owner,
            options.status, options.max_results, options.header)


if __name__ == '__main__':
  main()

